package org.jeecg.modules.wlhy.hyevent.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.enums.ReportPlatformEnum;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.third.amap.dto.MapDirectionDTO;
import org.jeecg.modules.third.amap.service.AmapService;
import org.jeecg.modules.third.jg.report.freight.information.constant.enums.AhUploadStatusEnum;
import org.jeecg.modules.third.jg.report.freight.information.constant.enums.ReportDocTypeEnum;
import org.jeecg.modules.third.jg.report.freight.information.dto.DriverDTO;
import org.jeecg.modules.third.jg.report.freight.information.dto.VehicleDTO;
import org.jeecg.modules.third.jg.report.freight.information.dto.shippingnote.AhShippingNoteDTO;
import org.jeecg.modules.third.jg.report.freight.information.dto.shippingnote.ShippingNoteDTO;
import org.jeecg.modules.third.jg.report.freight.information.model.R;
import org.jeecg.modules.third.jg.report.freight.information.service.AhReportPlatformService;
import org.jeecg.modules.wlhy.company.entity.HyCompanyConfig;
import org.jeecg.modules.wlhy.hydriver.entity.HyDriver;
import org.jeecg.modules.wlhy.hydriver.entity.HyDriverReport;
import org.jeecg.modules.wlhy.hydriver.service.IHyDriverReportService;
import org.jeecg.modules.wlhy.hydriver.service.IHyDriverService;
import org.jeecg.modules.wlhy.hyevent.service.AhRealtimeReportService;
import org.jeecg.modules.wlhy.hyvehicle.entity.HyVehicle;
import org.jeecg.modules.wlhy.hyvehicle.entity.HyVehicleReport;
import org.jeecg.modules.wlhy.hyvehicle.entity.HyVehicleType;
import org.jeecg.modules.wlhy.hyvehicle.service.IHyVehicleReportService;
import org.jeecg.modules.wlhy.hyvehicle.service.IHyVehicleService;
import org.jeecg.modules.wlhy.order.entity.HyOrder;
import org.jeecg.modules.wlhy.order.service.IHyOrderService;
import org.jeecg.modules.wlhy.report.impl.BaseReportService;
import org.jeecg.modules.wlhy.shipping.constant.ShippingPayStatus;
import org.jeecg.modules.wlhy.shipping.entity.HyShippingNote;
import org.jeecg.modules.wlhy.shipping.service.IHyShippingNoteService;
import org.jeecg.modules.wlhy.utils.HyCfgUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class AhRealtimeReportServiceImpl implements AhRealtimeReportService {

    @Autowired
    private IHyShippingNoteService hyShippingNoteService;

    @Autowired
    private IHyOrderService hyOrderService;

    @Autowired
    private IHyDriverService hyDriverService;

    @Autowired
    private IHyVehicleService hyVehicleService;

    @Resource
    private BaseReportService baseReportService;

    @Autowired
    private AmapService amapService;

    @Resource
    private AhReportPlatformService ahReportPlatformService;

    @Resource
    private IHyDriverReportService hyDriverReportService;

    @Resource
    private IHyVehicleReportService vehicleReportService;

    private void initReportConfig(HyCompanyConfig companyConfig) {
        this.ahReportPlatformService.setReportInfo(companyConfig.getReportUrl(),
                companyConfig.getReportUsername(),
                companyConfig.getReportPassword(),
                companyConfig.getReportPublickey(),
                companyConfig.getReportAppid(),
                companyConfig.getReportAppkey(),
                companyConfig.getReportAppsender(),
                companyConfig.getReportApprelease());
    }

    @Override
    public void reportStep1(HyShippingNote hyShippingNote, HyCompanyConfig companyConfig) {

        log.info("[安徽运单1实时上报] 开始上报实时运单1,{}", hyShippingNote.getShippingNoteNumber());
        this.initReportConfig(companyConfig);

        String needPay = HyCfgUtil.getCfgItem2("anhui_report","need_pay");
        if (StrUtil.isNotEmpty(needPay)) {
            if (!hyShippingNote.getShippingPayStatus().equals(ShippingPayStatus.支付完成.getValue())) {
                log.info("[安徽运单1实时上报] 该运单未支付完成,{}", hyShippingNote.getShippingNoteNumber());
                return;
            }
        }

        if ("1".equals(hyShippingNote.getUploadStatus())) {
            log.info("[安徽运单1实时上报] 该运单已完成整体上报,{}", hyShippingNote.getShippingNoteNumber());
            return;
        }

        //第1步成功了就不用上传了
        if (StrUtil.isNotEmpty(hyShippingNote.getUploadStatus()) && !hyShippingNote.getUploadStatus().equals("0")
                && (Integer.valueOf(hyShippingNote.getUploadStatus()).intValue() <= AhUploadStatusEnum.UPLOAD_STEP1_SUCCESS.getCode().intValue())) {
            log.info("[安徽运单1实时上报] 该运单1已上报,{}", hyShippingNote.getShippingNoteNumber());
            return;
        }

        //估计预计发货时间
        if (null == hyShippingNote.getStatusDtLoading()) {
            hyShippingNote.setStatusDtLoading(hyShippingNote.getStatusDtReceive());
        }

        //估计预计收货时间
        if (null == hyShippingNote.getStatusDtUnloading()) {
            hyShippingNote.setStatusDtUnloading(new Date());
        }

        //时效判断 运单生成时间<运单发货时间<运单实际收货时间
//        if (hyShippingNote.getStatusDtReceive().after(hyShippingNote.getStatusDtLoading())
//                || hyShippingNote.getStatusDtLoading().after(hyShippingNote.getStatusDtUnloading())) {
//            this.updateReportStatus(hyShippingNote.getShippingNoteNumber(),
//                    AhUploadStatusEnum.UPLOAD_STEP1_ERROR.getStatus(),
//                    "该运单时效存在错误，必须满足:运单创建时间<运单装货时间<运单卸货时间。",
//                    ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
//            log.info("[安徽运单1实时上报] 该运单时效存在错误，必须满足:运单创建时间<运单装货时间<运单卸货时间。 {}", hyShippingNote.getShippingNoteNumber());
//            return;
//        }
        //超载判断
//        HyVehicle hyVehicle = this.vehicleService.getById(ShippingNoteDb.getVehicleId());
//        if (ShippingNoteDb.getGoodsWeightLoading().compareTo(hyVehicle.getVehicleTonnage()) > 0 ) {
//            ShippingNoteDb.setUploadStatus(AhUploadStatusEnum.UPLOAD_STEP1_ERROR.getStatus());
//            ShippingNoteDb.setUploadDate(new Date());
//            ShippingNoteDb.setReportPlatformType(ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
//            ShippingNoteDb.setReportFailureReason("货物重量超过车辆核定载质量，货物重量: "+ShippingNoteDb.getGoodsWeightLoading()+"车辆核定载质量:"+hyVehicle.getVehicleTonnage());
//            this.hyShippingNoteService.updateById(ShippingNoteDb);
//            log.error("安徽监管上报超载 货物重量 {} > 核定载质量 {}", ShippingNoteDb.getGoodsWeightLoading(), hyVehicle.getVehicleTonnage());
//            return Result.error("货物重量超过车辆核定载质量，货物重量:" + ShippingNoteDb.getGoodsWeightLoading() + " ,车辆核定载质量:" + hyVehicle.getVehicleTonnage());
//        }

        //安徽分段上传运单1
        ShippingNoteDTO shippingNoteDTO = baseReportService.shippingNoteTOShippingNoteDTO(hyShippingNote, hyShippingNote.getCompanyId());
        //安徽ShippingNote
        AhShippingNoteDTO ahShippingNoteDTO = new AhShippingNoteDTO();
        BeanUtil.copyProperties(shippingNoteDTO, ahShippingNoteDTO, true);

        //运距 Distance （公里）
        //hyShippingNote.getTransportationDistance()一般情况下是没值的。如果轨迹有问题，可以通过在shippingnote表中手工指定公里数
        double distance = 0d;
        if (StrUtil.isEmpty(hyShippingNote.getTransportationDistance())) {
            //如果开启表示真实轨迹，0关闭表示用模拟轨迹的公里数
            HyOrder hyOrder = this.hyOrderService.getById(hyShippingNote.getOrderId());
            MapDirectionDTO mapDirectionDTO = this.amapService.getMapGpsOrder(hyOrder);
            if (ObjectUtil.isEmpty(mapDirectionDTO)) {
                log.info("[安徽运单1实时上报] :模拟轨迹数据不正确 ,{}", hyShippingNote.getShippingNoteNumber());
                return;
            }

            log.info("[安徽运单1实时上报]，模拟轨迹公里数{} {}", hyShippingNote.getShippingNoteNumber(), mapDirectionDTO.getDistance());
            distance = new BigDecimal(mapDirectionDTO.getDistance()).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();

        } else {
            distance = new BigDecimal(hyShippingNote.getTransportationDistance()).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
        }

        ahShippingNoteDTO.setDistance(String.valueOf(distance));
        //是否是大件运输 IsLargeSize 0非  1是
        ahShippingNoteDTO.setIsLargeSize("0");
        String postJsonString = JSONUtil.toJsonStr(ahShippingNoteDTO);

        String reporDocType = ReportDocTypeEnum.REPORT_DOC_TYPE_WLHY_YD1.getCode();
        ReportDocTypeEnum reportDocTypeEnum = ReportDocTypeEnum.getReportDocTypeEnumByVal(reporDocType);

        try{
            String reportResult = this.ahReportPlatformService.sendReport(reportDocTypeEnum, postJsonString, hyShippingNote.getShippingNoteNumber());
            if (StringUtils.isNotEmpty(reportResult)) {
                R result = JSON.parseObject(reportResult, R.class);
                boolean res = result.getCode() == 1001 && result.isSuccess() ? true : false;
                //上传运单第一步
                this.updateReportStatus(hyShippingNote.getShippingNoteNumber(),
                        res ? AhUploadStatusEnum.UPLOAD_STEP1_SUCCESS.getStatus() : AhUploadStatusEnum.UPLOAD_STEP1_ERROR.getStatus(),
                        res ? "" : result.getMsg()+result.getData(),
                        ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());

                return;
            } else {
                log.error("[安徽运单1实时上报]: 安徽监管平台响应报文错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            this.updateReportStatus(hyShippingNote.getShippingNoteNumber(),
                    AhUploadStatusEnum.UPLOAD_STEP1_ERROR.getStatus(),
                    e.getMessage(),
                    ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
            log.error("[安徽运单1实时上报]:安徽监管平台响应报文错误. {}", e.getMessage());
        }

        return;
    }

    @Override
    public void reportStep2(HyShippingNote hyShippingNote, HyCompanyConfig companyConfig) {

        log.info("[安徽运单2实时上报] 开始上报实时运单2,{}", hyShippingNote.getShippingNoteNumber());
        this.initReportConfig(companyConfig);

        if ("1".equals(hyShippingNote.getUploadStatus())) {
            log.info("[安徽运单2实时上报] 该运单已完成整体上报,{}", hyShippingNote.getShippingNoteNumber());
            return;
        }


        //第1步没成功不能上传
        if ("0".equals(hyShippingNote.getUploadStatus())) {
            log.error("[安徽运单2实时上报] 运单1没上报, {} {}", hyShippingNote.getShippingNoteNumber(), hyShippingNote.getUploadStatus());
            return;
        }

        if (StrUtil.isNotEmpty(hyShippingNote.getUploadStatus())
                && (Integer.valueOf(hyShippingNote.getUploadStatus()).intValue() > AhUploadStatusEnum.UPLOAD_STEP1_SUCCESS.getCode().intValue())) {
            log.info("[安徽运单2实时上报] 运单1上报状态不正确,{} {}", hyShippingNote.getShippingNoteNumber(), hyShippingNote.getUploadStatus());
            return;
        }

        //第2步成功了就不用上传了
        if (StrUtil.isNotEmpty(hyShippingNote.getUploadStatus())
                && (Integer.valueOf(hyShippingNote.getUploadStatus()).intValue() <= AhUploadStatusEnum.UPLOAD_STEP2_SUCCESS.getCode().intValue())) {
            log.info("[安徽运单2实时上报] 该运单2已上报,{} {}", hyShippingNote.getShippingNoteNumber(), hyShippingNote.getUploadStatus());
            return ;
        }

        ShippingNoteDTO shippingNoteDTO = baseReportService.shippingNoteTOShippingNoteDTOAhStep2(hyShippingNote);
        String postJsonString = JSONUtil.toJsonStr(shippingNoteDTO);
        String reporDocType = ReportDocTypeEnum.REPORT_DOC_TYPE_WLHY_YD2.getCode();
        ReportDocTypeEnum reportDocTypeEnum = ReportDocTypeEnum.getReportDocTypeEnumByVal(reporDocType);

        try{
            String reportResult = ahReportPlatformService.sendReport(reportDocTypeEnum, postJsonString, hyShippingNote.getShippingNoteNumber());
            if (StringUtils.isNotEmpty(reportResult)) {
                R result = JSON.parseObject(reportResult, R.class);
                boolean res = result.getCode() == 1001 && result.isSuccess() ? true : false;
                //上传运单第二步
                this.updateReportStatus(hyShippingNote.getShippingNoteNumber(),
                        res ? AhUploadStatusEnum.UPLOAD_STEP2_SUCCESS.getStatus() : AhUploadStatusEnum.UPLOAD_STEP2_ERROR.getStatus(),
                        res ? "" : result.getMsg()+result.getData(),
                        ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());

                return;
            } else {
                log.error("[安徽运单2实时上报]:安徽监管平台响应报文错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            this.updateReportStatus(hyShippingNote.getShippingNoteNumber(),
                    AhUploadStatusEnum.UPLOAD_STEP2_ERROR.getStatus(),
                    e.getMessage(),
                    ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
            log.error("[安徽运单2实时上报]:安徽监管平台响应报文错误. {}", e.getMessage());
        }

        return;
    }

    private void updateReportStatus(String shippingNoteNumber, String uploadStatus, String uploadFailureReason, Integer reportPlatformType) {

        this.hyShippingNoteService.update(new LambdaUpdateWrapper<HyShippingNote>()
                .eq(HyShippingNote::getShippingNoteNumber, shippingNoteNumber)
                .set(HyShippingNote::getUploadStatus, uploadStatus)
                .set(HyShippingNote::getReportFailureReason, uploadFailureReason)
                .set(HyShippingNote::getUploadDate, new Date())
                .set(HyShippingNote::getReportPlatformType, reportPlatformType)
        );

        return;
    }


    @Override
    public void reportDriver(HyShippingNote hyShippingNote, HyCompanyConfig companyConfig) {

        boolean bDriverUploadStatus = this.hyDriverReportService.checkUploadStatus(hyShippingNote.getDriverId(), hyShippingNote.getCompanyId(),
                ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
        if (bDriverUploadStatus) {
            log.info("[安徽司机忽略实时上报] 该司机已上报,{} {}", hyShippingNote.getShippingNoteNumber(), hyShippingNote.getDriverId());
            return;
        }

        log.info("[安徽司机实时上报] 开始上报实时司机,{}", hyShippingNote.getShippingNoteNumber());
        this.initReportConfig(companyConfig);

        HyDriver hyDriverDb = hyDriverService.getById(hyShippingNote.getDriverId());
        if (hyDriverDb == null) {
            log.info("未找到对应数据 {} {}", hyShippingNote.getShippingNoteNumber(), hyDriverDb.getDriverName());
            return;
        }

        try {
            DriverDTO driverDTO = baseReportService.hyDriverTODriverDTO(hyDriverDb);
            String jsonString = JSONUtil.toJsonStr(driverDTO);
            String reporDocType = ReportDocTypeEnum.REPORT_DOC_TYPE_WLHY_JSY.getCode();
            ReportDocTypeEnum reportDocTypeEnum = ReportDocTypeEnum.getReportDocTypeEnumByVal(reporDocType);

            String reportResult = ahReportPlatformService.sendReport(reportDocTypeEnum, jsonString, "司机");
            if (StringUtils.isNotEmpty(reportResult)) {
                R result = JSON.parseObject(reportResult, R.class);
                log.info("[安徽实时上报]更新司机上报回执信息, {} {}", hyShippingNote.getShippingNoteNumber(), result.getMsg());
                Thread.sleep(1000);
                return;
            }
        } catch (Exception e){
            e.printStackTrace();
        }

        return;
    }


    @Override
    public void reportVehicle(HyShippingNote hyShippingNote, HyCompanyConfig companyConfig) {

        boolean bVehicleUploadStatus = this.vehicleReportService.checkUploadStatus(hyShippingNote.getVehicleId(), hyShippingNote.getCompanyId(),
                ReportPlatformEnum.REPORT_PLATFORM_AH.getCode());
        if (bVehicleUploadStatus) {
            log.info("[安徽车辆忽略实时上报] 该车辆已上报,{} {}", hyShippingNote.getShippingNoteNumber(), hyShippingNote.getVehicleId());
            return;
        }

        log.info("[安徽车辆实时上报] 开始上报实时车辆,{}", hyShippingNote.getShippingNoteNumber());
        this.initReportConfig(companyConfig);

        HyVehicle hyVehiclDb = this.hyVehicleService.getById(hyShippingNote.getVehicleId());
        if(hyVehiclDb == null) {
            log.error("[安徽实时上报]未找到对应数据 {}", hyShippingNote.getShippingNoteNumber());
        }

        if (StringUtils.isEmpty(hyVehiclDb.getRoadTransportNumber())) {
            log.error("[安徽实时上报]车辆道路运输证不能为空 {} {}", hyShippingNote.getShippingNoteNumber(), hyVehiclDb.getVehicleNumber());
            return;
        }

        List<HyVehicleType> hyVehicleTypeList = this.hyVehicleService.getHyVehicleByPid("1");
        HyVehicleType hyVehicleType = hyVehicleTypeList.stream().filter(s->hyVehiclDb.getVehicleType().contains(s.getText())).findAny().orElse(null);
        if (hyVehicleType == null) {
            log.error("[安徽实时上报]车辆类型不存在 {} {}", hyShippingNote.getShippingNoteNumber(), hyVehiclDb.getVehicleNumber());
            return;
        }

        //载重量上限判断
        if (hyVehiclDb.getVehicleTonnage().intValue() > 90) {
            hyVehiclDb.setVehicleTonnage(new BigDecimal(41));
        }

        //吨位上限判断
        if (hyVehiclDb.getGrossMass().intValue() > 90) {
            hyVehiclDb.setGrossMass(new BigDecimal(48));
        }

        if (hyVehiclDb.getVehicleTonnage().compareTo(hyVehiclDb.getGrossMass()) > -1) {
            hyVehiclDb.setVehicleTonnage(new BigDecimal(41));
            hyVehiclDb.setGrossMass(new BigDecimal(48));
        }

        hyVehiclDb.setVehicleType(hyVehicleType.getValue());
        VehicleDTO vehicleDTO = baseReportService.hyVehicleDTOTOVehicleDTO(hyVehiclDb);
        String jsonString = JSONUtil.toJsonStr(vehicleDTO);
        String reporDocType = ReportDocTypeEnum.REPORT_DOC_TYPE_WLHY_CL.getCode();
        ReportDocTypeEnum reportDocTypeEnum = ReportDocTypeEnum.getReportDocTypeEnumByVal(reporDocType);

        try {
            String reportResult = ahReportPlatformService.sendReport(reportDocTypeEnum, jsonString, "车辆");
            if(StringUtils.isNotEmpty(reportResult)){
                R result = JSON.parseObject(reportResult, R.class);
                log.info("[安徽实时上报]更新车辆上报回执信息, {} ", JSONUtil.toJsonStr(result));
                Thread.sleep(1000);
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return;
    }

}
